package com.zdp.netty.chapter10.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * @Author zhengdp
 * @Description 文件服务器使用HTTP协议对外提供服务，当客户端通过浏览器访问文件服务器时，
 * 对访问路径进行检查，检查失败时返回HTTP 403错误，该页无法访问；
 * 如果校验通过，以链接的方式打开当前文件目录，每个目录或者文件都是个超链接，可以递归访问。
 * 如果是目录，可以继续递归访问它下面的子目录或者文件，
 * 如果是文件且可读，则可以在浏览器端直接打开，或者通过【目标另存为】下载该文件
 */
public class HttpFileServer {

    private static final String DEFAULT_URL = "/netty-learn";

    public void run(final int port, final String url) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup,workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 服务器接收请求，对request进行解码
                            socketChannel.pipeline().addLast("http-decoder", new HttpRequestDecoder());
                            // 将多个消息转换为单一的 FullHttpRequest或者FullHttpResponse（Http解码器在每个Http消息中会生成多个消息对象）
                            socketChannel.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
                            // 服务器返回响应，对response进行编码
                            socketChannel.pipeline().addLast("http-encoder", new HttpResponseEncoder());
                            // 支持异步发送大的码流（大的文件传输），以便防止占用过多的内存，导致Java内存溢出
                            socketChannel.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
                            socketChannel.pipeline().addLast("fileServerHandler", new HttpFileServerHandler(url));
                        }
                    });

            ChannelFuture f = b.bind("10.0.228.150",port).sync();
            System.out.println("Http File Server Start, url is : http://10.0.228.150:" + port + "/" +  url);
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        String url = DEFAULT_URL;
        new HttpFileServer().run(8080,url);
    }

}
